/**
 * 特化接口测试用例
 *
 * Created by yangyunze on 2021/01/04.
 */
const chai = require('chai');
const should = chai.should(); // eslint-disable-line no-unused-vars
chai.use(require('chai-http'));

const common = require('./../../common');
const Administrator = require('./../../../models/administrator');
const uri = require('./../uri');
const benchmark = require('./../../../benchmark/analyse-files/specialization');

module.exports = describe('/POST files/:id/file-elements.json', function () {
  const administrator = new Administrator();
  let projectVersion = {};
  let specializedData = {};
  let specializedChildren = {};
  let fileElements = [];
  let otherElementId;
  let otherFileId;
  const newUserIds = [];
  function url(fileId) {
    return `/files/${fileId}/file-elements.json`;
  }

  function treeUrl(elementId) {
    return `/file-elements/${elementId}/tree.json`;
  }

  function getElement(fileElements, name) {
    let elementId = null;
    let fileId = null;
    fileElements.forEach((element) => {
      if (element.functionName !== name) {
        return;
      }
      elementId = element.functionId;
      fileId = element.fileId;
    });
    return { fileId, elementId };
  }

  before(function (done) {
    administrator.login()
      .then(() => administrator.createRandomTester())
      .then((tester) => {
        newUserIds.push(tester.userId);
        return tester.createRandomProject('c++');
      })
      .then((project) => project.createRandomVersion('c++'))
      .then((res) => {
        projectVersion = res;
        done();
      })
      .catch(done);
  });
  after(function (done) {
    administrator.removeUsers(newUserIds)
      .then(() => {
        done();
      })
      .catch(done);
  });

  common.should.be.user(uri, url, 'post');
  common.should.be.tester(uri, url, 'post');

  // 正常特化
  it('it should SPECIALIZE element successfully', function (done) {
    projectVersion.getAllFunctions(benchmark)
      .then((elements) => {
        fileElements = elements;
        const { elementId, fileId } = getElement(elements, benchmark.specialization.normal.name);
        otherFileId = fileId;
        otherElementId = elementId;
        const { requestBody } = benchmark.specialization.normal;
        requestBody.fileElementId = elementId;
        chai.request(uri)
          .post(url(fileId))
          .set('Authorization', `Bearer ${projectVersion.project.creator.token.accessToken}`)
          .send(requestBody)
          .end((err, res) => {
            res.should.have.status(200);
            common.should.be.specializedElement(res.body);
            specializedData = res.body;
            done();
          });
      });
  });

  // 特化结果验证
  it('it should CREATE specialized elements successfully', function (done) {
    chai.request(uri)
      .get(treeUrl(specializedData.functionId))
      .set('Authorization', `Bearer ${projectVersion.project.creator.token.accessToken}`)
      .end((err, res) => {
        specializedChildren = res.body.tree.children;
        res.should.have.status(200);
        common.should.be.elementsTree(res.body);
        common.should.be.equal.tree(
          res.body.tree,
          benchmark.result.normal.tree
        );
        done();
      });
  });

  // 二次特化
  it('it should SPECIALIZE child element successfully', function (done) {
    const { elementId, fileId } = getElement(
      specializedChildren,
      benchmark.specialization.subSpec.name
    );
    const { requestBody } = benchmark.specialization.subSpec;
    requestBody.fileElementId = elementId;
    chai.request(uri)
      .post(url(fileId))
      .set('Authorization', `Bearer ${projectVersion.project.creator.token.accessToken}`)
      .send(requestBody)
      .end((err, res) => {
        res.should.have.status(200);
        common.should.be.specializedElement(res.body);
        done();
      });
  });

  // 不可对非模板元素进行特化
  it('it should fail to specialize with a non-template element', function (done) {
    const { elementId, fileId } = getElement(
      fileElements,
      benchmark.specialization.notTemplateElement
    );
    chai.request(uri)
      .post(url(fileId))
      .set('Authorization', `Bearer ${projectVersion.project.creator.token.accessToken}`)
      .send({ fileElementId: elementId })
      .end((err, res) => {
        res.should.have.status(412);
        done();
      });
  });

  // 重复的特化内容
  it('it should fail to specialize with the duplicate data', function (done) {
    const { elementId, fileId } = getElement(fileElements, benchmark.specialization.normal.name);
    const { requestBody } = benchmark.specialization.normal;
    requestBody.fileElementId = elementId;
    chai.request(uri)
      .post(url(fileId))
      .set('Authorization', `Bearer ${projectVersion.project.creator.token.accessToken}`)
      .send(requestBody)
      .end((err, res) => {
        res.should.have.status(409);
        done();
      });
  });

  // 文件不存在
  it('it should fail to specialize when file not exists', function (done) {
    chai.request(uri)
      .post(url('000000000000000000000000'))
      .set('Authorization', `Bearer ${projectVersion.project.creator.token.accessToken}`)
      .end((err, res) => {
        res.should.have.status(404);
        common.should.be.errorMessage(res.body);
        done();
      });
  });

  // 元素不存在
  it('it should fail to specialize when element not exists', function (done) {
    const [{ fileId }] = fileElements;
    chai.request(uri)
      .post(url(fileId))
      .set('Authorization', `Bearer ${projectVersion.project.creator.token.accessToken}`)
      .send({ fileElementId: '000000000000000000000000' })
      .end((err, res) => {
        res.should.have.status(404);
        common.should.be.errorMessage(res.body);
        done();
      });
  });

  // 不可对他人项目中的元素进行特化
  it('it should fail to specialize when the project is not yours', function (done) {
    let newUser;
    administrator.createRandomTester()
      .then((newTester) => {
        newUserIds.push(newTester.userId);
        newUser = newTester;
        return newTester.getToken();
      })
      .then(() => {
        chai.request(uri)
          .post(url(otherFileId))
          .set('Authorization', `Bearer ${newUser.token.accessToken}`)
          .send({ fileElementId: otherElementId })
          .end((err, res) => {
            res.should.have.status(404);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });
});
